/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.task.zkex.list.grid;

import cn.easyplatform.lang.Lang;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.request.ListSelectRequestMessage;
import cn.easyplatform.messages.request.SimpleRequestMessage;
import cn.easyplatform.messages.vos.datalist.ListSelectedRowVo;
import cn.easyplatform.spi.service.ListService;
import cn.easyplatform.type.DeviceType;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.type.ListRowVo;
import cn.easyplatform.web.contexts.Contexts;
import cn.easyplatform.web.ext.zul.Actionbox;
import cn.easyplatform.web.ext.zul.Datalist;
import cn.easyplatform.web.service.ServiceLocator;
import cn.easyplatform.web.task.event.EventEntry;
import cn.easyplatform.web.task.event.FieldEntry;
import cn.easyplatform.web.task.OperableHandler;
import cn.easyplatform.web.task.BackendException;
import cn.easyplatform.web.task.zkex.list.PanelSupport;
import cn.easyplatform.web.task.zkex.list.menu.SimpleColumnMenu;
import cn.easyplatform.web.utils.PageUtils;
import cn.easyplatform.web.utils.WebUtils;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.HtmlBasedComponent;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.SelectEvent;
import org.zkoss.zul.Listhead;
import org.zkoss.zul.Listitem;
import org.zkoss.zul.Menupopup;
import org.zkoss.zul.Window;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class ActionboxGridBuilder extends
        AbstractSelectableGridBuilder<Actionbox> {

    private Window window;

    private List<ListRowVo> selectedItems;

    private int[] selectIndex;

    private Object[] referenceValues;

    public ActionboxGridBuilder(OperableHandler mainTaskHandler,
                                Datalist listExt, Actionbox ref, Component anchor) {
        super(mainTaskHandler, listExt, ref, anchor);
    }

    protected Component createContent() {
        if (listExt.isMultiple()) {
            clickType = 0;
            selectedItems = new ArrayList<ListRowVo>();
            if (ref.isCheckmark()) {
                Object value = ref.getRealValue();
                if (value != null && !Strings.isBlank(value.toString())) {
                    if (value instanceof String)
                        referenceValues = ((String) value).split(ref.getSeparator());
                    else if (value instanceof Object[])
                        referenceValues = (Object[]) value;
                }
            }
        } else
            clickType = 2;
        listExt.setEvent("select()");
        Component c = super.createContent();
        if (ref.isCombo() || listExt.isMultiple())
            selectIndex = PageUtils.getActionboxIndexes(ref.getMapping(),
                    layout.getHeaders());
        window = new Window();
        if (Strings.isBlank(ref.getTitle()))
            window.setTitle(layout.getName());
        else
            window.setTitle(ref.getTitle());
        window.setMaximizable(true);
        window.setBorder(true);
        window.setClosable(true);
        window.setSizable(true);
        window.addEventListener(Events.ON_CLOSE, this);
        if (!Strings.isBlank(getEntity().getHeight()))
            window.setHeight(getEntity().getHeight());
        else
            window.setHeight("450px");
        if (!Strings.isBlank(getEntity().getWidth()))
            window.setWidth(getEntity().getWidth());
        else
            window.setWidth("550px");
        window.appendChild(c);
        return window;
    }

    @Override
    protected void close() {
        ListService dls = ServiceLocator
                .lookup(ListService.class);
        dls.doClose(new SimpleRequestMessage(mainTaskHandler.getId(), listExt
                .getId()));
        window.detach();
        window = null;
        if (ref.getDropdown() != null) {
            ref.getDropdown().detach();
            ref.close();
        }
    }

    @Override
    public void select(Event evt) {
        if (ref.isMultiple() || ref.isCombo()) {
            if (selectedItems != null) {
                Object[] selectedObject = new Object[selectedItems.size()];
                StringBuilder sb = null;
                if (selectIndex.length > 1)
                    sb = new StringBuilder();
                int index = 0;
                for (ListRowVo rv : selectedItems) {
                    selectedObject[index] = rv.getData()[selectIndex[0]];
                    if (sb != null) {
                        sb.append(rv.getData()[selectIndex[1]]);
                        if (index < selectedItems.size() - 1)
                            sb.append(ref.getSeparator());
                    }
                    index++;
                }
                ref.setRealValue(selectedObject);
                if (sb != null)
                    ref.setLabel(sb.toString());
                Events.postEvent(Events.ON_CHANGE, ref, selectedObject);
            } else {
                ListRowVo rv = listExt.getSelectedItem().getValue();
                Object[] selectedObject = new Object[1];
                selectedObject[0] = rv.getData()[selectIndex[0]];
                ref.setRealValue(selectedObject);
                if (selectIndex.length > 1) {
                    Object val = rv.getData()[selectIndex[1]];
                    ref.setRawValue(val == null ? "" : val.toString());
                }
                Events.postEvent(Events.ON_CHANGE, ref, selectedObject);
            }
        } else {
            ListRowVo rv = listExt.getSelectedItem().getValue();
            ListService dls = ServiceLocator
                    .lookup(ListService.class);
            ListSelectedRowVo srv = new ListSelectedRowVo(listExt.getId(), isCustom() ?
                    rv.getData() : rv.getKeys());
            if (getAnchor() != null) {
                rv = WebUtils.getAnchorValue(getAnchor());
                srv.setTarget(new ListSelectedRowVo(mainTaskHandler
                        .getComponent().getId(), rv.getKeys()));
            } else if (mainTaskHandler instanceof PanelSupport) {
                PanelSupport ps = (PanelSupport) mainTaskHandler;
                srv.setTarget(new ListSelectedRowVo(ps.getList().getComponent()
                        .getId(), null));
            }
            IResponseMessage<?> resp = dls
                    .doSelect(new ListSelectRequestMessage(mainTaskHandler
                            .getId(), srv));
            if (!resp.isSuccess())
                throw new BackendException(resp);
            ref.setAttribute("selectEvent", "on");
            if (getAnchor() != null)
                WebUtils.setAnchor(getAnchor());
            try {
                String[] updateField = (String[]) resp.getBody();
                mainTaskHandler.refresh(new EventEntry<FieldEntry>(
                        new FieldEntry(updateField, true)));
            } finally {
                ref.removeAttribute("selectEvent");
            }
        }
        close();
    }

    @Override
    protected void setMenupopup(HtmlBasedComponent head) {
        if (Contexts.getEnv().getDeviceType().equalsIgnoreCase(DeviceType.AJAX.getName())) {
            Menupopup popup = new SimpleColumnMenu(head, this, getEntity()
                    .isExport(), getEntity().isPrint());
            popup.setId(listExt.getId() + "_popup");
            window.appendChild(popup);
            ((Listhead) head).setMenupopup(popup.getId());
        }
    }

    @Override
    protected void onSelect(SelectEvent<Component, Set<Component>> evt) {
        for (Component c : evt.getSelectedItems()) {
            Listitem item = (Listitem) c;
            ListRowVo row = item.getValue();
            ListRowVo sel = null;
            for (ListRowVo rv : selectedItems) {
                if (rv.getKeys() == null) {
                    if (Lang.equals(rv.getData(), row.getData())) {
                        sel = rv;
                        break;
                    }
                } else if (Lang.equals(rv.getKeys(), row.getKeys())) {
                    sel = rv;
                    break;
                }
            }
            if (sel == null)
                selectedItems.add(row);
        }
        for (Component c : evt.getUnselectedItems()) {
            Listitem item = (Listitem) c;
            ListRowVo row = item.getValue();
            ListRowVo sel = null;
            for (ListRowVo rv : selectedItems) {
                if (rv.getKeys() == null) {
                    if (Lang.equals(rv.getData(), row.getData())) {
                        sel = rv;
                        break;
                    }
                } else if (Lang.equals(rv.getKeys(), row.getKeys())) {
                    sel = rv;
                    break;
                }
            }
            if (sel != null)
                selectedItems.remove(sel);
        }
        referenceValues = null;
    }

    @Override
    public boolean validate(Component c) {
        Listitem item = (Listitem) c;
        if (selectedItems != null) {
            ListRowVo row = item.getValue();
            for (ListRowVo rv : selectedItems) {
                if (row.getKeys() == null) {
                    if (Lang.equals(rv.getData(), row.getData())) {
                        item.setSelected(true);
                        return true;
                    }
                } else {
                    if (Lang.equals(rv.getKeys(), row.getKeys())) {
                        item.setSelected(true);
                        return true;
                    }
                }
            }
        }
        if (referenceValues != null && referenceValues.length > 0) {
            ListRowVo row = item.getValue();
            for (Object val : referenceValues) {
                if (Lang.equals(val, row.getData()[selectIndex[0]])) {
                    selectedItems.add(row);
                    item.setSelected(true);
                    return true;
                }
            }
        }
        return false;
    }

}
